package com.ajx.platform.buildingmronitor.websocket;


import com.ajx.platform.buildingmronitor.config.ApplicationContextRegister;
import com.ajx.platform.buildingmronitor.model.HightBuildCameraEvent;
import com.ajx.platform.buildingmronitor.service.HightBuildCameraEventService;
import com.ajx.platform.buildingmronitor.service.HightBuildCameraService;
import com.ajx.platform.buildingmronitor.utils.CodeUtils;
import com.ajx.platform.buildingmronitor.utils.DateUtils;
import com.ajx.platform.buildingmronitor.utils.FileUtil;
import com.anjuxing.platform.common.base.User;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

// 继承于WebSocketAdapter
// WebSocketAdapter是一个比WebSocketListener更为强大的适配器，它可以提供完整有效的Session检查。
public class EventSocket extends WebSocketAdapter {

    private static Logger logger = LoggerFactory.getLogger(EventSocket.class);

    // 解决不能直接注入service
    ApplicationContext act = ApplicationContextRegister.getApplicationContext();
    HightBuildCameraService hightBuildCameraService = act.getBean(HightBuildCameraService.class);
    HightBuildCameraEventService hightBuildCameraEventService = act.getBean(HightBuildCameraEventService.class);


    public static void printHexString(byte[] b) {
        logger.info("printHexString:::::::::::::::");
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            logger.info(hex.toUpperCase());
        }

    }

    public static byte[] getUTF8BytesFromGBKString(String gbkStr) {
        int n = gbkStr.length();
        byte[] utfBytes = new byte[3 * n];
        int k = 0;
        for (int i = 0; i < n; i++) {
            int m = gbkStr.charAt(i);
            if (m < 128 && m >= 0) {
                utfBytes[k++] = (byte) m;
                continue;
            }
            utfBytes[k++] = (byte) (0xe0 | (m >> 12));
            utfBytes[k++] = (byte) (0x80 | ((m >> 6) & 0x3f));
            utfBytes[k++] = (byte) (0x80 | (m & 0x3f));
        }
        if (k < utfBytes.length) {
            byte[] tmp = new byte[k];
            System.arraycopy(utfBytes, 0, tmp, 0, k);
            return tmp;
        }
        return utfBytes;
    }

    @Override
    public void onWebSocketConnect(Session sess) {

        logger.info("onWebSocketConnect:::::::::::::::::::::::::::::::::::::");
        try {
            // 重置默认的 maxBinaryMessageSize 大小，默认65536 bit (64 kb)
            sess.getPolicy().setMaxBinaryMessageSize(5*1024*1024);// 5Mb
            super.onWebSocketConnect(sess);
            logger.info("Socket Connected: " + sess);

            //send sn
            SJHLPRIPCProtocol.SJH_PACKET_HEADER stPacket = new SJHLPRIPCProtocol.SJH_PACKET_HEADER();
            stPacket.nSync.set(0xCDDCCDDC);
            stPacket.nVersion.set(0x0);
            stPacket.nFlag.set((short) 0);
            stPacket.nType.set((short) 0);
            stPacket.nRev1.set((short) 0);
            stPacket.nRev2.set((short) 0);
            stPacket.nCmdID.set(0xA0);
            stPacket.nLength.set(0x0);

            ByteBuffer structbuf = stPacket.getByteBuffer();
            structbuf.order(ByteOrder.LITTLE_ENDIAN);
            byte[] bytes = new byte[stPacket.size()];
            structbuf.get(bytes, 0, bytes.length);
            printHexString(bytes);
            logger.info("");

            structbuf.position(0);
            // 向server发送......
            sess.getRemote().sendBytes(structbuf);
            logger.info("send sn packet");

        } catch (Throwable t) {
            t.printStackTrace(System.err);
        }
    }

    // 接收client发送的字符串信息
    @Override
    public void onWebSocketText(String message) {
        logger.info("onWebSocketText:::::::::::::::::::::::::::::::::::::");
        super.onWebSocketText(message);
        logger.info("Received TEXT message: " + message);
    }

    // 接收client发送的二进制信息
    @Override
    public void onWebSocketBinary(byte[] payload, int offset, int len) {
        logger.info("onWebSocketBinary:::::::::::::::::::::::::::::::::::::");
        try {
            // 保存图片信息
            Map pictureMessageMap = new HashMap();
            logger.info("onWebSocketBinary: " + len);
            super.onWebSocketBinary(payload, offset, len);

            logger.info("");
            SJHLPRIPCProtocol.SJH_PACKET_HEADER stPacket = new SJHLPRIPCProtocol.SJH_PACKET_HEADER();
            ByteBuffer tmpBuf = ByteBuffer.wrap(payload, 0, stPacket.size());
            tmpBuf.order(ByteOrder.LITTLE_ENDIAN);
            stPacket.setByteBuffer(tmpBuf, 0);
            logger.info("stPacket infos:");
            //logger.info("nSync: " + stPacket.nSync);
            logger.info("nCmdID:" + stPacket.nCmdID);
            logger.info("nLength:" + stPacket.nLength);

            logger.info("switch 值"+stPacket.nCmdID.get());
            switch ((int) stPacket.nCmdID.get()) {
                case 0xA1:        //sn   相机--> server
                {
                    logger.info("sn   相机--> server");
                    logger.info("stSNPacket infos:");
                    SJHLPRIPCProtocol.SJH_NET_DEV_SN_VER stSNPacket = new SJHLPRIPCProtocol.SJH_NET_DEV_SN_VER();

                    byte[] aSN = new byte[(int) stPacket.nLength.get()];

                    /*
                     * payload   源数组
                     * stPacket.size() 源数组要复制的起始位置
                     * aSN       目的数组
                     * destPos:  目的数组放置的起始位置
                     * stPacket.nLength.get()     复制的长度
                     **/
                    System.arraycopy(payload, stPacket.size(), aSN, 0, (int) stPacket.nLength.get());
                    logger.info("aSN::::::::");
                    printHexString(aSN);
                    logger.info("");
                    ByteBuffer snBuf = ByteBuffer.wrap(aSN);
                    //snBuf.order(ByteOrder.LITTLE_ENDIAN);
                    stSNPacket.setByteBuffer(snBuf, 0);
                    //nSync sn号
                    logger.info("nSync: " + stSNPacket.szSN);
                    logger.info("nCmdID:" + stSNPacket.szVer);


                    SJHLPRIPCProtocol.SJH_PACKET_HEADER stHeader = new SJHLPRIPCProtocol.SJH_PACKET_HEADER();
                    SJHLPRIPCProtocol.SJH_NET_DEV_DATE_TIME stDateTime = new SJHLPRIPCProtocol.SJH_NET_DEV_DATE_TIME();
                    stHeader.nSync.set(0xCDDCCDDC);
                    stHeader.nVersion.set(0x0);
                    stHeader.nFlag.set((short) 0);
                    stHeader.nType.set((short) 0xB8);
                    stHeader.nRev1.set((short) 0);
                    stHeader.nRev2.set((short) 0);
                    stHeader.nCmdID.set(0xA9);
                    stHeader.nLength.set(stDateTime.size());

                    Date dtToday = new Date();
                    stDateTime.u16Year.set((short) (1900 + dtToday.getYear()));
                    stDateTime.u8Month.set((byte) dtToday.getMonth());
                    stDateTime.u8Day.set((byte) dtToday.getDay());
                    stDateTime.u8Hour.set((byte) dtToday.getHours());
                    stDateTime.u8Minute.set((byte) dtToday.getMinutes());
                    stDateTime.u8Second.set((byte) dtToday.getSeconds());
                    stDateTime.u32MisSecond.set(0x0);
                    logger.info("DateTime info");
                    logger.info(stDateTime.u16Year + "-" + stDateTime.u8Month + "-" + stDateTime.u8Day + " " + stDateTime.u8Hour + ":" + stDateTime.u8Minute + ":" + stDateTime.u8Second);


                    ByteBuffer structbuf = stHeader.getByteBuffer();
                    ByteBuffer stDTBuf = stDateTime.getByteBuffer();
                    structbuf.order(ByteOrder.LITTLE_ENDIAN);
                    stDTBuf.order(ByteOrder.LITTLE_ENDIAN);

                    byte[] bytes = new byte[stHeader.size() + stDateTime.size()];

                    structbuf.get(bytes, 0, stHeader.size());
                    printHexString(bytes);
                    logger.info("");

                    stDTBuf.get(bytes, stHeader.size(), stDateTime.size());
                    printHexString(bytes);
                    logger.info("");

                    ByteBuffer sendBuf = ByteBuffer.wrap(bytes);
                    //sendBuf.order(ByteOrder.LITTLE_ENDIAN);
                    structbuf.position(0);
                    //发送信息到服务端
                    this.getSession().getRemote().sendBytes(sendBuf);
                    logger.info("");
                    logger.info("send datetime packet");

                    DoHeatBeat dhb = new DoHeatBeat(this.getSession());

                    Thread th = new Thread(dhb);
                    th.start();

                }
                break;

                case 0xA5: {
                    logger.info("取图片 相机--> server");
                    SJHLPRIPCProtocol.SJH_LICENSE_RESULT stPlateResult = new SJHLPRIPCProtocol.SJH_LICENSE_RESULT();
                    byte[] aPlateResult = new byte[(int) stPacket.nLength.get()];
                    System.arraycopy(payload, stPacket.size(), aPlateResult, 0, (int) stPacket.nLength.get());
                    //printHexString(aPlateResult);
                    //logger.info("");
                    ByteBuffer plateResBuf = ByteBuffer.wrap(aPlateResult);
                    stPlateResult.setByteBuffer(plateResBuf, 0);
                    plateResBuf.order(ByteOrder.LITTLE_ENDIAN); //转换大小端
                    logger.info("SJH_LICENSE_RESULT infos");
                    // 设备序列号
                    String devSn = stPlateResult.szSN.toString();
                    System.out.println("SN:" + devSn);
                    System.out.println("查询group:::"+hightBuildCameraService.findGroupCamera(devSn));
                    String groupId = hightBuildCameraService.findGroupCamera(devSn);
                    String photoRootPath = CodeUtils.getProperties("application.properties", "file.upload.path1");
                    String localFilePath = photoRootPath;

                    if (StringUtils.isNotBlank(groupId)) {
                        // 同一组，同一时间点（相差10s的为一组事件）
                        Map param = new HashMap();
                        Date currentDate = com.anjuxing.platform.common.util.DateUtils.getCurrentTime();
                        param.put("groupId",groupId);
                        param.put("currentDate",currentDate);
                        HightBuildCameraEvent event = hightBuildCameraEventService.getEventByParam(param);
                        if (event == null) {
                            System.out.println("event == null");
                            HightBuildCameraEvent entity = new HightBuildCameraEvent();
                            localFilePath = photoRootPath+DateUtils.getCurrentTimeStr()+"/";
                            entity.preInsert(new User());
                            entity.setGroupId(groupId);
                            entity.setLocalFilePath(localFilePath);
                            entity.setSnapshotTime(currentDate);
                            hightBuildCameraEventService.save(entity);
                            System.err.println("event == null"+localFilePath);
                        }else {
                            System.out.println("event != null");
                            localFilePath = event.getLocalFilePath();
                            System.err.println("event != null"+localFilePath);
                        }
                    }else {logger.warn("请设置相机组别！");}
                    logger.info("DevID:" + stPlateResult.szDevID);
                    // 设备名称
                    logger.info("DevName:" + stPlateResult.szDevName);
/*                    byte[] aPlate = new byte[SJHLPRIPCProtocol.SJHLPRIPCConstant.SJH_LICENSE_MAX];
                    for (int i = 0; i < SJHLPRIPCProtocol.SJHLPRIPCConstant.SJH_LICENSE_MAX; i++) {
                        aPlate[i] = (byte) stPlateResult.szLicense[i].get();
                    }
                    //logger.info("\n aPlate hex");
                    //printHexString(aPlate);

                    byte[] aColor = new byte[SJHLPRIPCProtocol.SJHLPRIPCConstant.SJH_LICENSE_COLOR_MAX];
                    for (int i = 0; i < SJHLPRIPCProtocol.SJHLPRIPCConstant.SJH_LICENSE_COLOR_MAX; i++) {
                        aColor[i] = (byte) stPlateResult.szColor[i].get();
                    }


                    String plate = new String(aPlate, "GBK");
                    logger.info("车牌Plate:" + plate);
                    String plateColor = new String(aColor, "GBK");
                    logger.info("Plate color:" + plateColor);*/

                    RandomAccessFile randomAccessFile = null;
                    FileChannel fileChannel = null;
                    //取图片信息(备注)   。。。。。。。
                    // 大图
                    logger.info("dwImageBigFileLen:" + stPlateResult.dwImageBigFileLen.get());
                    ByteBuffer tmpBuf1 = ByteBuffer.wrap(payload, stPacket.size() + stPlateResult.size(),(int)stPlateResult.dwImageBigFileLen.get());

                    String bigfileName = DateUtils.getCurrentTimeMillisStr()+".jpg";
                    // 无当前文件夹则创建
                    FileUtil.createFile(localFilePath,bigfileName);
                    //randomAccessFile = new RandomAccessFile("D:\\javajar\\carImage\\"+Math.random()+".jpg", "rw");	//字节文件photoPath
                    randomAccessFile = new RandomAccessFile(localFilePath + bigfileName, "rw");	//字节文件
                    randomAccessFile.seek(randomAccessFile.length());           //防止覆盖原文件内容
                    fileChannel = randomAccessFile.getChannel();
                    fileChannel.write(tmpBuf1);	//写入字节
                    logger.info("写入大图成功");
                    // 小图
                    logger.info("dwImageSmallFileLen:" + stPlateResult.dwImageSmallFileLen);
                    //randomAccessFile = new RandomAccessFile("D:\\javajar\\carImage\\"+Math.random()+".jpg", "rw");	//字节文件
                    Thread.sleep(100);
                    String smallfileName = DateUtils.getCurrentTimeMillisStr()+".jpg";
                    randomAccessFile = new RandomAccessFile(localFilePath + smallfileName, "rw");	//字节文件
                    randomAccessFile.seek(randomAccessFile.length());
                    fileChannel = randomAccessFile.getChannel();
                    ByteBuffer tmpBuf2 = ByteBuffer.wrap(payload, stPacket.size()+stPlateResult.size() + (int)stPlateResult.dwImageBigFileLen.get(), (int)stPlateResult.dwImageSmallFileLen.get());
                    fileChannel.write(tmpBuf2);
                    logger.info("写入小图成功");
                }
                break;

                default:
                    break;
            }


	        /*
	    	Student student = new Student();
	    	student.setByteBuffer(ByteBuffer.wrap(payload), 0);
	    	logger.info("student infos:");
	        logger.info("student gender:" + student.gender);
	        logger.info("student name:" + student.name);
	        logger.info("student age:" + student.birth.year);
	        logger.info("student grades:" + student.grades[2]);

	    	 String helloHex = DatatypeConverter.printHexBinary(payload);
	    	 logger.info("Received Binary message offset: " + offset + "len: " + len);
	        logger.info("Received Binary message: " + helloHex);
	        logger.info("student name:" + student.name + " birth: " + student.birth);
	        */

        } catch (Throwable t) {
            t.printStackTrace(System.err);
        }
    }

    @Override
    public void onWebSocketClose(int statusCode, String reason) {
        logger.info("onWebSocketClose:::::::::::::::::::::::");
        super.onWebSocketClose(statusCode, reason);
        logger.info("Socket Closed: [" + statusCode + "] " + reason);
    }

    @Override
    public void onWebSocketError(Throwable cause) {
        super.onWebSocketError(cause);
        cause.printStackTrace(System.err);
    }

    public class DoHeatBeat implements Runnable {
        private Session wssession;

        public DoHeatBeat(Session wssession) {
            this.wssession = wssession;
        }

        public void run() {
            try {
                while (true) {
                    SJHLPRIPCProtocol.SJH_PACKET_HEADER stPacket = new SJHLPRIPCProtocol.SJH_PACKET_HEADER();
                    stPacket.nSync.set(0xCDDCCDDC);
                    stPacket.nVersion.set(0x0);
                    stPacket.nFlag.set((short) 0);
                    stPacket.nType.set((short) 0);
                    stPacket.nRev1.set((short) 0);
                    stPacket.nRev2.set((short) 0);
                    stPacket.nCmdID.set(0xA2);
                    stPacket.nLength.set(0x0);

                    ByteBuffer structbuf = stPacket.getByteBuffer();
                    structbuf.order(ByteOrder.LITTLE_ENDIAN);
                    byte[] bytes = new byte[stPacket.size()];
                    structbuf.get(bytes, 0, bytes.length);
                    printHexString(bytes);
                    logger.info("");

                    structbuf.position(0);
                    wssession.getRemote().sendBytes(structbuf);
                    logger.warn("send Heatbeat packet");
                    Thread.sleep(10 * 1000);
                }
            } catch (Throwable t) {
                wssession.close();
                t.printStackTrace(System.err);
            }
        }
    }
}
